////////////////////////////////////////////////////////////////////////////////
// This file has general utilities that can be used in javascript code.
//
// Currently the list of utilities is as follows:
//		$								Short for document.getElementById();
//		Util.onReturn					Handles RETURN key press
//		Util.doHookUp					Adds a hookup method to the onload event of the body
//		Util.showHide					Show or hides an HTML element
//		Util.showMessages				Shows messages from XML-based created object (for tables)
//		Util.isAlpha					Determines if a string is alphanumeric
//		Util.isBlank					Determines if a string is blank
//		Util.isNumeric					Determines if a string is a number
//		Util.isArray					Determines if an object is an array
//		Util.numberInRange				Determines if a number/string is between a certain range (inclusive). Number E [a,b]
//		Util.findElementWithClass		Finds a nested element of the one specified with the specified class attribute
//
//
//	Disclaimer
//		Some of these functions were borrowed from the Open Source
//		DWRUtil library.
////////////////////////////////////////////////////////////////////////////////

/**
 * Class class.<br>
 */
var Class = {
	
	/**
	 * Creates a class and invokes the initialize method. 
	 */	
  	create: function() {
    	return function() { 
			this.initialize.apply(this,arguments); 
		}
  	}
};

//Namespace declaration
function Util() {}

/**
 * Enables you to react to return being pressed in an input
 * For example:
 * <code>&lt;input type="text" onkeypressed="Util.onReturn(event, methodName)"/&gt;</code>
 * @param event The event object for Netscape browsers
 * @param action Method name to execute when return is pressed
 */
Util.onReturn = function(event, action)
{
    if (!event)
    {
        event = window.event;
    }

    if (event && event.keyCode && event.keyCode == 13)
    {
        action();
    }
};

/**
** ------------------------------
** Util.doHookUp
** ------------------------------
**	This function allows the script to add a hookUp method
**  listening for the onLoad event of the page body.
** The unload feature works for IE only.
**
** Params
** ------
**	  funcLoad		- The function to listen for the onLoad Event
**	  funcUnload	- The function to listen for the onUnload Event
**
** Returns
** -------
**	Nothing
*/
Util.doHookUp = function(funcLoad, funcUnload){
	if( funcLoad == null){
		return;
	}
	if ( typeof window.addEventListener != "undefined" ){
		window.addEventListener( "load", funcLoad, false );
	}
	// for IE
	else if (typeof window.attachEvent != "undefined"){
		window.attachEvent( "onload", funcLoad );
		if( funcUnload != null ){
			window.attachEvent( "onunload", funcUnload );
		}
	}
	else if ( window.onload != null ) {
			var oldOnload = window.onload;
			window.onload = function ( e ) {
				oldOnload( e );
				funcLoad();
			};
	}else{
		window.onload = funcLoad;
	}
}

/**
** ------------------------------
** Util.showHide
** ------------------------------
**	This function allows for showing and hiding
**  html Elements. Use the second parameter to specify
**  if to show or hide the element.
**
** Params
** ------
**	  elem    		- The HTML element to show or hide
**	  show      	- Boolean value that specifies if the eleme should be shown
**
** Returns
** -------
**	Nothing
*/
Util.showHide = function(elem, show){

	if(show){
		elem.style.display = "block";
	}else{
		elem.style.display = "none";
	}

}

/**
** ------------------------------
** Util.isHidden
** ------------------------------
**	This function determines if the received
*   object is hidden or not
**
** Params
** ------
**	  elem    		- The HTML element evaluate
**
** Returns
** -------
**	true if the elem is hidden, false otherwise
*/
Util.isHidden = function(elem){

	if( elem.style.display == "none" ){
		return true;
	}

	return false;
}

/**
 * Find the element in the current HTML document with the given id, or if more
 * than one parameter is passed, return an array containing the found elements.
 * Any non-string arguments are left as is in the reply.
 * This function is inspired by the prototype library however it probably works
 * on more browsers than the original.
 * Technically speaking this will not work on IE5.0 because it uses Array.push
 * however it is expected that this will only be used in conjunction with
 * engine.js (which makes up for this omission). If you are using this function
 * without engine.js and want IE5.0 compatibility then you should arrange for
 * a replacement for Array.push.
 * @see http://www.getahead.ltd.uk/dwr/script-general.html
 */
function $()
{
    var elements = new Array();
	
    for (var i = 0; i < arguments.length; i++)
    {
        var element = arguments[i];
        if (typeof element == 'string')
        {
            if (document.getElementById)
            {
                element = document.getElementById(element);
            }
            else if (document.all)
            {
                element = document.all[element];
            }
        }

        if (arguments.length == 1)
        {
            return element;
        }

        elements.push(element);
    }

    return elements;
}

function parent$(){
	return _top$(parent, arguments);
}

/**
	top$ was modified to find the "navView" element with a bottom-up parent search
*/
function top$(){

	var findFrame = false;
	winParent= parent;

	while(!findFrame){
		if( winParent.frames["navView"] != null ){
			win = winParent.frames["navView"];
			findFrame=true;
		} else {
			winParent = winParent.parent;
		}
	}
	return _top$(win, arguments);
}

/**
 * Same as $, but this one finds it in the "top"-most window
 */
function _top$(win, args)
{
    var elements = new Array();

    for (var i = 0; i < args.length; i++)
    {
        var element = args[i];
        if (typeof element == 'string')
        {
            if (document.getElementById)
            {
                element = win.document.getElementById(element);
            }
            else if (document.all)
            {
                element = win.document.all[element];
            }
        }

        if (args.length == 1)
        {
            return element;
        }

        elements.push(element);
    }

    return elements;
}

/*
** Shows the messages in the main Panel
** Data must have a messages field with a property called
** message that is an array of Message objects.
**
** Data must have a property called 'messages'. That field
** can have one attribute called message, that can be an array
** or a string. That information is printed in the main Panel
*/
Util.showMessages = function(data){
	if( data == null || data.messages == null || data.messages.message == null){
		return;
	}

	//msg is:
	//	message
	//	severity
	var msgs = data.messages.message;
	if(msgs == null ){
		return;
	}
	if( msgs instanceof Array){
		for(var i=0; i < msgs.length; i++){
			msgUtil.Message.logError(msgs[i].message);
		}
	}else{
		msgUtil.Message.logError(msgs.message);
	}
}


//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////// DOM ELEMENT MANIPULATION ////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
Util.dom = function(){};

/**
** ------------------------------
** Util.dom.toObject
** ------------------------------
**	This function receives a documentElement (DOM)
**  object and returns its javascript object representation.
**  i.e.
**	  For a DOM that represents the following structure:
**      <data low='3'>
**			<value1 id="value1ID">value1 inner text</value1>
**			<value2 id="value2ID">value2 inner text</value2>
**			<message>the first message</message>
**			<message>the second message</message>
**		</data>
**
**	  It returns an object with the following properties:
**		obj.nodeName = 'data'
**		obj.low = '3'
**		obj.value1.nodeName = 'value1'
**		obj.value1.id   = 'value1ID'
**		obj.value1.innerText = 'value1 inner text'
**		obj.value2.nodeName ='value2'
**		obj.value2... (same as value1)
**		obj.message.length = 2    (note: this is an array)
**		obj.message[0].innerText = 'the first message'
**		... and so on.
**
**	An object always has a 'nodeName' property (with the same name as the
**	tag the object represents) and a 'innerText' property with the value
**  of the enclosed text of the tag (if any).
**
**  How to use:
**		var myObj = util.toObject(documentElement);
**
**  NOTE: avoid using this function with large XMLs as it may hang
**  	  the browser.
**	(IMPORTANT: always leave the second parameter empty)
**
** Params
** ------
**	  doc			- A documentElement object, representing an XML
**
** Returns
** -------
**	  A Javscript object that has properties and subobjects that match
**	  those on the XML.
*/
Util.dom.toObject=function(doc, parent){

	var obj = new Object();

	var elems = doc.childNodes;
	var attrs = doc.attributes;

	//Check for Text Types
	if( doc.nodeType == 3){
		parent.innerText = doc.nodeValue;
		return;
	}

	var tagName = doc.nodeName;
	obj.nodeName = tagName;

	//Process this Tag's attributes first
	if( attrs != null ){
		for(var i=0; i < attrs.length; i++){
			//alert(attrs[i].name + " = " + attrs[i].value);
			obj[attrs[i].name] = attrs[i].value;
		}
	}

	//if there are no child elements, then we can exit because we are in a leaf
	//Don't process the elems, but add the current object to its parent
	var processElements = (elems != null && elems.length > 0);
	if( processElements ){
		//process every child tag. This is recursive
		for(var i=0; i < elems.length; i++){
			Util.dom.toObject(elems[i], obj);
		}
	}

	if( parent != null){
		//if we have a parent, then we attach to it.
		Util.dom.addElementToParent(doc, tagName, obj, parent);
	}else{
		//we are finished! just return the new object
		return obj;
	}
}

/**
** ------------------------------
** Util.dom.addElementToParent
** ------------------------------
**	This is a PRIVATE function.
**	It adds the obj to the parent.
**	If the parent already has more than one tag with the
**  same name as 'tagName' the it creates an array for the
**  parents property for this tagName.
**  i.e.: parent.<tagName> is an Array.
**  If not a "standard" property is set
**
** Params
** ------
**	  doc			- A documentElement object. It is the DOM for the parent object
**	  tabName		- The name of the tag of 'obj'
**	  obj			- The child object to attach to 'parent'
**	  parent		- The destination object for the 'obj'
**
** Returns
** -------
**	  Nothing
*/
Util.dom.addElementToParent=function(doc, tagName, obj, parent){
	//check if there are already any elements with this tag.
	//If multiple elements with the same tag, then create an array
	if( Util.dom.hasMoreEqualTags(doc, tagName) ){
		var arr = parent[tagName];
		if( arr == null ){
			//alert("Creating array");
			arr = new Array();
			arr[0] = obj;
		}else{
			//alert("adding a new member to the array");
			arr[arr.length] = obj;
		}
		parent[tagName] = arr;
	}else{
		parent[tagName] = obj;
	}
}

/**
** ------------------------------
** Util.dom.hasMoreEqualTags
** ------------------------------
**	This is a PRIVATE function
**
** Params
** ------
**	  doc			- A documentElement object, representing an XML
**	  tagName		- A tag to be searched in the doc.
**
** Returns
** -------
**	  true if the doc element has more than one tagName's childNodes
**	  false otherwise.
*/
Util.dom.hasMoreEqualTags=function(doc, tagName){
	if(doc == null ){
		return false;
	}
	var parent = doc.parentNode;
	if( parent == null ){
		return false;
	}

	return parent.getElementsByTagName(tagName).length > 1;
}

//new namespace declaration
Util.valid = new Object();
/**
** ------------------------------
** Util.valid.isAlpha
** ------------------------------
**	Validate if the String passed as parameter is alphanumeric or not
**	Valid characters: A-Z, a-z, 0-9
**
** Params
** ------
**	  str			- The string to test
**
** Returns
** -------
**	  true if the string is a non-blank, non-null alphanumeric
*/
Util.valid.isAlpha = function(str){

	if( str == null ){
		return false;
	}

	var re = new RegExp("[a-zA-Z0-9]+", "i");

	return str.match(re);
}

/**
** ------------------------------
** Util.valid.isBlank
** ------------------------------
**	Validate if the String passed as parameter is blank (and not null)
**
** Params
** ------
**	  str			- The string to test
**
** Returns
** -------
**	  true if the string is a blank (if it is null returns false)
*/
Util.valid.isBlank = function(str){
	if( str == null ){
		return false;
	}

	return str == "";
}

/**
** ------------------------------
** Util.valid.isNumeric
** ------------------------------
**	Validate if the String passed as parameter is a valid integer
**
**
** Params
** ------
**	  str			- The string to test
**
** Returns
** -------
**	  true if the string is a valid integer and not null and not blank.
*/
Util.valid.isNumeric = function(str){
	if( str == null ){
		return false;
	}

	var re = RegExp("^[-]{0,1}[0-9]+$");
	return str.match(re);
}



/**
** ------------------------------
** Util.valid.isArray
** ------------------------------
**	Validate if the object passed as parameter is an instance of Array
**
**
** Params
** ------
**	  obj			- The obj to test
**
** Returns
** -------
**	  true if the obj is instance of Array
*/
Util.valid.isArray = function(obj){

	try{
		return obj.length > 0;
	}catch(e){}

	return false;
}

/**
** ------------------------------
** Util.valid.isPositiveNumeric
** ------------------------------
**	Validate if the String passed as parameter is a valid integer
**	and is grater or equal than 0.
**
**
** Params
** ------
**	  str			- The string to test
**
** Returns
** -------
**	  true if the string is a valid integer and not null and not blank.
**    and it is grater or equal than 0 (zero).
*/
Util.valid.isPositiveNumeric=function(str){
	if( str == null ){
		return false;
	}

	var re = RegExp("^[0123456789]+$");
	return str.match(re);
}

/* Valida q sea un float positivo o negativo
 *
 */
Util.valid.isFloat = function(str) {
    if (str == null) {
        return false;
    }

    var re = new RegExp("^-{0,1}\\d*\\.{0,1}\\d+$");
    var my = new String(str);
    return my.match(re);

}

/* Valida q sea un float positivo
 *
 */
Util.valid.isPositiveFloat = function(str) {
    if (str == null) {
        return false;
    }

    var re = new RegExp("^\\d*\\.{0,1}\\d+$");
    var my = new String(str);
    return my.match(re);
    
}

/* Valida q sea un entero positivo
 */
Util.valid.isPositiveInteger = function(str) {
    if (str == null) {
        return false;
    }

    var re = RegExp("^\\d+$");
    var my = new String(str);
    return my.match(re);
}

/**
 * Valida q pase la expresion regular
 */
Util.valid.validatesRegexp=function(str, regExpStr) {
    if( str == null ){
        return false;
    }

    var re = RegExp(regExpStr);
    return str.match(re);
}

/**
** ------------------------------
** Util.valid.numberInRange
** ------------------------------
**	Validates that the number passed as a parameter is in the range
**  specified. The range is inclusive (lower bound and upper bound)
**
** Params
** ------
**	  str			- The string/number to test
**	  lowerBound	- The lower bound of the range (can be a string or a number)
**	  upperBound	- The upper bound of the range (can be a string or a number)
**
** Returns
** -------
**	  true if the string / number is grater or equal than lowerBound and
**	  lower or equal than upperBound
**	If any of the values is not a valid number or can not be
**  converted to a number, it returns false;
*/
Util.valid.numberInRange = function(str, lowerBound, upperBound){

	if( str == null || lowerBound == null || upperBound == null ){
		return false;
	}

	var num = parseInt(str);
	if( num == NaN ) return false;

	var lowerNum = parseInt(lowerBound);
	if( lowerNum == NaN ) return false;

	var upperNum = parseInt(upperBound);
	if( upperNum == NaN ) return false;

	var valid = lowerNum <= num && num <= upperNum;

	return valid;

}

/**
** ------------------------------
** Util.findElementWithClass
** ------------------------------
**	Finds a nested html element inside the 'element' specified
** as parameter that contains in its 'class' attribute the value specified
** in 'class'
** It searches recursively inside child elements too. (depth first)
**
** Params
** ------
**	element		- an HTML element that has inner htmls
**	class		- the value of the class attribute the inner element must have
**
** Returns
** -------
**	  the first inner element that has the value of the class attribute set
**	to 'class'
*/
Util.findElementWithClass = function(element, clazz){
	var childs = element.childNodes;

	if( childs != null ){
		for(var i=0; i < childs.length; i++){
			var elem = Util.findElementWithClass(childs[i], clazz);
			if( elem != null ){
				return elem;
			}
		}
	}
	/* Matches any css class inside a class declaration.
	 * Example:
	 * 		class="aClass"							=>		^clazz$	
	 * 		class=" aClass"							=>		\s{1,}clazz$		
	 * 		class="aClass otherClass"				=>		^clazz\s{1,}
	 * 		class="other1 aClass other2"			=>		\s{1,}clazz\s{1,}
	 * Obs:
	 * 	\s 		->	blank space	
	 *  {1,}	->	One or more occurrences
	 *  ngonzalez, acukiernic
	 */
/*	var expression = "^" + clazz + "$|\s{1,}" + clazz + "$|^" + clazz + "\s{1,}|\s{1,}" + clazz + "\s{1,}";
	var regExp = new RegExp(expression, "gi");
	TODO -> To be fixed. When clazz looks like this: "#xxxx" or "#xxxx#" or "xxxx#", we should escape the '#'
	
	*/

	var regExp = new RegExp(clazz, "gi");

	if( regExp.test(element.className) ){
		return element;
	}

	return null;
}

/* Returns true if the param is empty
 */
function isEmpty(param) {
	return (param.value == "");
}

/* Returns the scrollTop of the first parent <div>
 * Used in table.css */
function getScrollTop(obj) {
	var par = obj;
	while (true) {
		par = par.parentElement;

		if (par.className  == 'overflowTable') {
			return par.scrollTop;
		}
	}
}

/* Checks wether the number is even or odd. */
function isEven(param) {
	return ((param % 2) == 0);
}

/*
 * Remove the given class name from the element?s className property list.
 * @author adrian.m.cukiernik / modified by nicolas.gonzalez 
 */
function removeClassName(elem, aClass) {
    var newList = new Array();
   	var curList = elem.className.split(' ');

    for (var i = 0; i < curList.length; ++i) {
    	if ( curList[i] != aClass ) {
           newList.push(curList[i]);
		}
	}
	elem.className = newList.join(' ');
}

/*
** Calculates the path for the disabled image
*/
Util.getDisabledImagePath = function( src )
{
	var tmp = src.split( '.' );
	// Very elegant -but troublesome- approach that needed to be simplified
	// to make it properly work when domains and dot separeted path elements
	// were present in the image path. If adding an element to the splitted
	// array, the join needs different 'connectors' on each step, because
	// simply rejoining with '.' will cause an extra dot to be added right
	// before the '_disabled' segment causing the resulting URL to be incorrect.
	//tmp.splice( tmp.length - 1, 0, '_disable' );
	//var lastVal = tmp[ tmp.length - 1 ];
	//tmp[ tmp.length - 1 ] = '.' + lastVal;
	//return tmp.join( '' );
	tmp[ tmp.length - 2 ] += '_disable';
	return tmp.join( '.' );
}

/*
** Calculates the path for the enabled image
*/
Util.getEnabledImagePath = function( src )
{
	return src.replace( /_disable/, '' );
}

/*
 * Turns a button to disabled appearance
 */
Util.disableButton = function( btn )
{
	if ( btn.disabled )
		return;

	btn.disabled=true;
	btn.style.cursor = "default";

	// Change the pixmap if is an image 
	if ( btn.src != null )
		btn.src = Util.getDisabledImagePath( btn.src );
}

/*
 * Turns a button to enabled appearance
 */
Util.enableButton = function( btn )
{
	if ( !btn.disabled )
		return;

	btn.disabled=false;
	btn.style.cursor = "pointer";

	// Change the pixmap if is an image 
	if ( btn.src != null )
		btn.src = Util.getEnabledImagePath( btn.src );
}


/* **********************************************************************************************************************************
 * 
 * Functions for Loopback
 * 
 * 
 * **********************************************************************************************************************************
 */

/**
 * Private function for Loopback and enableIP purposes.<br>
 * Invokes a pop Up with certain params.
 * 
 * @param {Object} url Url to invoke
 */
function popUpLoopbackEnableIp(url) {
	var params = "resizable=1,width=324,height=245";
	
	window.open(url, '', params);
}

function enableLoopbackLoadingDiv() {
	var popUpBody = document.getElementById("popUpBody");
	popUpBody.style.marginLeft = 0;
	loadingPanel.show();
}

/**
 * Private function for Loopback Purpose.<br> 
 * Assembles a query string.<br>
 * Pattern:
 * 	first=xxxxx&second=yyyyyyy 
 * 
 * @param {Object} lportName
 * @param {Object} vlan
 * @param {Object} vid
 * @param {Object} operationName
 */
function assembleParametersQueryString(lportName, vlan, vid, operationName) {
	var str = "lportName=" + lportName + "&vlan=" + vlan + "&vid=" + vid + "&operationName=" + operationName;
	
	return str;
}

